package com.cyc.common.exception;

import com.cyc.common.model.ApiResult;
import com.cyc.common.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;

import java.util.HashMap;
import java.util.Map;

/**
 * @author fei
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {MissingServletRequestParameterException.class})
    public ApiResult<Void> missingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.error("missing servlet request parameter exception:{}", ex.getMessage());
        return ApiResult.fail(SystemErrorType.ARGUMENT_NOT_VALID);
    }

    @ExceptionHandler(value = {MultipartException.class})
    public ApiResult<Void> uploadFileLimitException(MultipartException ex) {
        log.error("upload file size limit:{}", ex.getMessage());
        String message = ex.getRootCause().getMessage();
        SystemErrorType fileUploadSizeLimit = null;
        if (message.contains("UT000054")) {
            fileUploadSizeLimit = SystemErrorType.FILE_UPLOAD_SIZE_LIMIT;
        } else if (message.contains("UT000020")) {
            fileUploadSizeLimit = SystemErrorType.FILE_UPLOAD_SIZE_SUM_LIMIT;
        }
        return ApiResult.fail(fileUploadSizeLimit);
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ApiResult<Void> serviceException(MethodArgumentNotValidException ex) {
        log.error("service exception:{}", ex.getMessage());
        Map<String, String> errorMap = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errorMap.put(fieldName, errorMessage);
        });
        return ApiResult.result(SystemErrorType.ARGUMENT_NOT_VALID.getCode(), errorMap.toString(), null);
    }

    @ExceptionHandler(value = {BaseException.class})
    public ApiResult<Void> baseException(BaseException ex) {
        log.error("base exception:{}", ex.getMessage());
        return ApiResult.fail(ex.getErrorType());
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    public ApiResult<Void> methodNotAllowedException(HttpRequestMethodNotSupportedException ex) {
        log.error("method not allowed exception:{}", ex.getMessage());
        return ApiResult.fail(SystemErrorType.GATEWAY_METHOD_NOT_ALLOWED);
    }


    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResult<Void> exception(Exception ex) {
        log.error("internal server error", ex);
        return ApiResult.fail();
    }

    @ExceptionHandler(value = {Throwable.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResult<Void> throwable(Throwable t) {
        log.error("internal server error", t);
        return ApiResult.fail();
    }

    @ExceptionHandler(value = {ServiceException.class})
    public ApiResult<Void> serviceException(ServiceException e) {
        log.error("service exception:{}", e.getErrorType().getMsg());
        return ApiResult.fail(e.getErrorType());
    }

    @ExceptionHandler(value = {DataErrorException.class})
    public ApiResult<Void> dataErrorException(DataErrorException e) {
        log.error("service exception:{}", e.getMessage());
        if (StringUtils.isBlank(e.getMessage())) {
            return ApiResult.fail(e.getErrorType());
        } else {
            return ApiResult.fail(e.getErrorType(), e.getMessage(), e.getMessage());
        }
    }
}